#include <memory>
#include <iostream>
#include <functional>
#include <atomic>
using namespace std;

//--------------------------------------
//We can Get Use the sharePtr implement the Use the Based Class Ptr point ths Derived object ,the we can Call the destructor function by the Based Ptr
//The Implement is following



//解决多线程问题下，引用计数访问出现问题

template <class T>
    class sharePtr{
        typedef sharePtr<T> Self;
        T* m_ptr;
        // int *count;
        atomic<int>* count;// 应该让引用计数时原子的，防止并发访问时出现问题
        //否则引用计数就会出现问题
        function<void(T*)> _del;
        public:
        T* get()
        {
            return m_ptr;
        }
        int Usecount()
        {
            return *count;
        }

        //用这种初始化构造函数有个好处，就是即是说你是<class A>,也依然会以delete B来默认释放，C++的标准实际也是有如此设计的方案
        //但是依然还是需要定制删除器，来解决数组释放问题
        template<typename T2>
        sharePtr(T2* p)
        :m_ptr(p)
        ,count(new atomic<int>(1))
        {
            _del = [p](void* ){delete p;};
        }
        //提供定制删除器
        template<typename T2,typename Del>
        sharePtr(T2* p,Del del)
        :m_ptr(p)
        ,_del(del)
        ,count(new atomic<int>(1))
        {
            
        }
        sharePtr()
        :m_ptr(nullptr)
        ,count(new atomic<int>(1))
        {
        }
        Self operator=(const Self& ptr)
        {
            if(this ==&ptr)
            {
                return *this;
            }
            release();
            m_ptr = ptr.m_ptr;
            count = ptr.count;
            (*count)++;
            return *this;
        }
        sharePtr(const Self& ptr)
        :m_ptr(ptr.m_ptr)
        ,count(ptr.count)
        {
            if(count && *count>0)
            {
                ++*count;
            }
        }
        T* operator->()
        {
            return m_ptr;
        }
        T& operator*()
        {
            return *m_ptr;
        }
        ~sharePtr()
        {
            release();
        }
        void release()
        {
            if(--*count ==0)
            {
                _del(m_ptr);
                delete count;
                count = nullptr;
                m_ptr = nullptr;
            }
        }
    };

